
#include "ShaderProgram.h"
#include "..\FileUtils.h"

ShaderProgram::ShaderProgram(const std::string& vertexFileName, const std::string& fragmentFileName)
	: m_program(0)
{
	initWithFileName(vertexFileName, fragmentFileName);
}

void ShaderProgram::release()
{
	releaseShader(&m_program);
}

void ShaderProgram::use()
{
	glUseProgram(getProgram());
}

void ShaderProgram::releaseShader(GLuint* shader)
{
	if (shader != nullptr && *shader > 0)
	{
		glDeleteShader(*shader);
		*shader = 0;
	}
}

void ShaderProgram::initWithFileName(const std::string& vertexFileName, const std::string& fragmentFileName)
{
	if (vertexFileName.empty() || fragmentFileName.empty())	return;
	std::string vSource, fSource;
	FileUtils::getInstance()->getStringWithFileName(vertexFileName, &vSource);
	FileUtils::getInstance()->getStringWithFileName(fragmentFileName, &fSource);
	initWithFileSource(vSource, fSource);
}

void ShaderProgram::initWithFileSource(const std::string& vertexSource, const std::string& fragmentSource)
{
	m_program = glCreateProgram();
	bool succeed = disposeShader(vertexSource, VERTEX) && disposeShader(fragmentSource, FRAGMENT);
	if (succeed)
	{
		glLinkProgram(getProgram());
		succeed = verificationShader(m_program, GL_LINK_STATUS, "program");
	}
	if (!succeed)	m_program = 0;
}

bool ShaderProgram::disposeShader(const std::string& source, ShaderKind kind)
{
	std::string s = "#version 330 core\n" + source;
	GLchar * p = (GLchar *)s.c_str();
	GLuint shaderId = glCreateShader(kind == VERTEX ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
	glShaderSource(shaderId, 1, &p, NULL);
	glCompileShader(shaderId);

	bool ret = verificationShader(shaderId, GL_COMPILE_STATUS, kind == VERTEX ? "vertex" : "fragment");
	if (ret) glAttachShader(getProgram(), shaderId);
	releaseShader(&shaderId);
	return ret;
}

bool ShaderProgram::verificationShader(GLuint shaderId, GLuint glStatus, const GLchar* shaderLog)
{
	GLint success;
	GLchar* statusStr = glStatus == GL_COMPILE_STATUS ? "compilation" : "link";
	glGetShaderiv(shaderId, glStatus, &success);
	if (!success)
	{
		GLchar infoLog[512];
		glGetShaderInfoLog(shaderId, 512, NULL, infoLog);
		std::cout << "error: Shader " << shaderLog << " " << statusStr << " failed,\nerror log:" << infoLog << std::endl;
	} else
		std::cout << "Shader " << shaderLog << " " << statusStr << " compilation succeed" << std::endl;
	return (bool)success;
}





